#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>

using namespace std;
using namespace cv;

class MyHist{
public:
    //像素计数
    int R_pixel[256];
    int G_pixel[256];
    int B_pixel[256];
    //累计分布
    double R_distro[256];
    double G_distro[256];
    double B_distro[256];
    int rows;
    int cols;
    int sum;
    MyHist(){
	rows = 0;
	cols = 0;
	sum = 0;
    }
    void calc(Mat& img){
        clear();
        rows = img.rows;
        cols = img.cols;
        sum = 0;
        for(int i=0;i<rows;i++){
        	for(int j=0;j<cols;j++){
        		B_pixel[img.at<Vec3b>(i,j)[0]]++;
        		G_pixel[img.at<Vec3b>(i,j)[1]]++;
        		R_pixel[img.at<Vec3b>(i,j)[2]]++;
        		sum++;
        	}
        }
        double tmp[3] = {0};//BGR
        for (int i=0;i<256;i++){
        	tmp[0] += B_pixel[i];
        	tmp[1] += G_pixel[i];
        	tmp[2] += R_pixel[i];
        	B_distro[i] = tmp[0]/sum;
        	G_distro[i] = tmp[1]/sum;
        	R_distro[i] = tmp[2]/sum;
        }
        
    }
    int normalizeHist(Mat& res){
    	if (res.rows != rows || res.cols != cols){
    		return -1;
    	}
    	for(int i=0;i<rows;i++){
    		for(int j=0;j<cols;j++){
    			res.at<Vec3b>(i,j)[0] = B_distro[res.at<Vec3b>(i,j)[0]]*255 + 0.5;
    			//(N-1)T + 0.5
    			res.at<Vec3b>(i,j)[1] = G_distro[res.at<Vec3b>(i,j)[1]]*255 + 0.5;
    			res.at<Vec3b>(i,j)[2] = R_distro[res.at<Vec3b>(i,j)[2]]*255 + 0.5;
    		}
    	}
    	return 0;
    }
    void visualize(Mat& histImg){
	for (int i=1;i<256;i++){
	    //cout<<B_distro[i-1]<<" "<<G_distro[i-1]<<" "<<R_distro[i-1]<<endl;
	    //line(histImg,Point(i-1,255-B_distro[i-1]*255),Point(i,255-B_distro[i]*255),Scalar(255,0,0),2,CV_AA);
	    //line(histImg,Point(i-1,255-G_distro[i-1]*255),Point(i,255-G_distro[i-1]*255),Scalar(0,255,0),2,CV_AA);
	    //line(histImg,Point(i-1,255-R_distro[i-1]*255),Point(i,255-R_distro[i-1]*255),Scalar(0,0,255),2,CV_AA);
	    //for distro
	    line(histImg,Point(i-1,255-B_pixel[i-1]*255/sum),Point(i,255-B_pixel[i]*255/sum),Scalar(255,0,0),2,CV_AA);
	    line(histImg,Point(i-1,255-G_pixel[i-1]*255/sum),Point(i,255-G_pixel[i]*255/sum),Scalar(0,255,0),2,CV_AA);
	    line(histImg,Point(i-1,255-R_pixel[i-1]*255/sum),Point(i,255-R_pixel[i]*255/sum),Scalar(0,0,255),2,CV_AA);
	}
    }
    void clear(){
        for (int i=0;i<256;i++){
            R_pixel[i] = 0;
            G_pixel[i] = 0;
            B_pixel[i] = 0;
            R_distro[i] = 0;
            G_distro[i] = 0;
            B_distro[i] = 0;
        }
        rows = 0;
        cols = 0;
        sum = 0;
    }
};


class MyGrayHist{
public:
    //像素计数
    int pixel[256];
    double distro[256];
    int rows;
    int cols;
    int sum;
    MyGrayHist(){
	rows = 0;
	cols = 0;
	sum = 0;
    }
    void calc(Mat& img){
        clear();
        rows = img.rows;
        cols = img.cols;
        sum = 0;
        for(int i=0;i<rows;i++){
        	for(int j=0;j<cols;j++){
        		pixel[img.at<uchar>(i,j)]++;
        		sum++;
        	}
        }
        double tmp = 0;
        for (int i=0;i<256;i++){
        	tmp += pixel[i];
        	distro[i] = tmp/sum;
        }
        
    }
    int normalizeHist(Mat& res){
    	if (res.rows != rows || res.cols != cols){
    		return -1;
    	}
    	for(int i=0;i<rows;i++){
    		for(int j=0;j<cols;j++){
    			res.at<uchar>(i,j) = distro[res.at<uchar>(i,j)]*255 + 0.5;
    			//(N-1)T + 0.5
    		}
    	}
    	return 0;
    }
    void visualize(Mat& histImg){
	for (int i=1;i<256;i++){
	    //cout<<B_distro[i-1]<<" "<<G_distro[i-1]<<" "<<R_distro[i-1]<<endl;
	    line(histImg,Point(i-1,255-distro[i-1]*255),Point(i,255-distro[i]*255),Scalar(255),2,CV_AA);
	    line(histImg,Point(i-1,255-pixel[i-1]*255/sum),Point(i,255-pixel[i]*255/sum),Scalar(255),2,CV_AA);
	}
    }
    void clear(){
        for (int i=0;i<256;i++){
            pixel[i] = 0;
            distro[i] = 0;
        }
        rows = 0;
        cols = 0;
        sum = 0;
    }
};

